combobox: Move area and menu to .ui file
authorDaniel Boles <dboles@src.gnome.org>
Sat, 21 Jan 2017 20:23:27 +0000 (20:23 +0000)
committerDaniel Boles <dboles@src.gnome.org>
Sat, 21 Jan 2017 21:34:46 +0000 (21:34 +0000)
Now that priv->area is guaranteed to be constructed by us, and not
passed in by a user, we can move it to the .ui file and stop manually
managing its lifetime altogether. And once the area is there, we can
move the menu there too (and stop pointlessly destroying/rebuilding it).

gtk/gtkcombobox.c
gtk/ui/gtkcombobox.ui

index 229f44852d9a6e0a3afec4097bc294f84367a719..b4cfc07780c78635c4418f5ca64f22b331556903 100644 (file)
@@ -286,11 +286,6 @@ static void     gtk_combo_box_model_row_changed    (GtkTreeModel     *model,
                                                     GtkTreeIter      *iter,
                                                     gpointer          data);
 
-/* menu */
-static void     gtk_combo_box_menu_setup           (GtkComboBox      *combo_box);
-static void     gtk_combo_box_menu_destroy         (GtkComboBox      *combo_box);
-
-
 static gboolean gtk_combo_box_menu_button_press    (GtkWidget        *widget,
                                                     GdkEventButton   *event,
                                                     gpointer          user_data);
@@ -973,7 +968,14 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
   gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, box);
   gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, button);
   gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, arrow);
+  gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, area);
+  gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, popup_widget);
   gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_button_toggled);
+  gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_button_press);
+  gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_activate);
+  gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_key_press);
+  gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_show);
+  gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_hide);
 
   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COMBO_BOX_ACCESSIBLE);
   gtk_widget_class_set_css_name (widget_class, "combobox");
@@ -1001,17 +1003,30 @@ gtk_combo_box_cell_editable_init (GtkCellEditableIface *iface)
   iface->start_editing = gtk_combo_box_start_editing;
 }
 
+static gboolean
+gtk_combo_box_row_separator_func (GtkTreeModel      *model,
+                                  GtkTreeIter       *iter,
+                                  GtkComboBox       *combo)
+{
+  GtkComboBoxPrivate *priv = combo->priv;
+
+  if (priv->row_separator_func)
+    return priv->row_separator_func (model, iter, priv->row_separator_data);
+
+  return FALSE;
+}
+
 static void
 gtk_combo_box_init (GtkComboBox *combo_box)
 {
   GtkComboBoxPrivate *priv;
   GtkCssNode *widget_node;
   GtkStyleContext *context;
+  GtkTreeMenu *menu;
 
   combo_box->priv = gtk_combo_box_get_instance_private (combo_box);
   priv = combo_box->priv;
 
-  priv->popup_widget = NULL;
   priv->wrap_width = 0;
 
   priv->active = -1;
@@ -1033,6 +1048,7 @@ gtk_combo_box_init (GtkComboBox *combo_box)
   priv->id_column = -1;
 
   g_type_ensure (GTK_TYPE_ICON);
+  g_type_ensure (GTK_TYPE_TREE_MENU);
   gtk_widget_init_template (GTK_WIDGET (combo_box));
 
   gtk_widget_add_events (priv->button, GDK_SCROLL_MASK);
@@ -1048,6 +1064,17 @@ gtk_combo_box_init (GtkComboBox *combo_box)
                                                      gtk_combo_box_allocate,
                                                      gtk_combo_box_render,
                                                      NULL, NULL);
+
+  menu = GTK_TREE_MENU (priv->popup_widget);
+  _gtk_tree_menu_set_wrap_width (menu, priv->wrap_width);
+  _gtk_tree_menu_set_row_span_column (menu, priv->row_column);
+  _gtk_tree_menu_set_column_span_column (menu, priv->col_column);
+  _gtk_tree_menu_set_row_separator_func (menu,
+                                         (GtkTreeViewRowSeparatorFunc)gtk_combo_box_row_separator_func,
+                                         combo_box, NULL);
+  gtk_menu_attach_to_widget (GTK_MENU (menu),
+                             GTK_WIDGET (combo_box),
+                             NULL);
 }
 
 static void
@@ -1335,17 +1362,8 @@ gtk_combo_box_remove (GtkContainer *container,
 
   gtk_widget_queue_resize (GTK_WIDGET (container));
 
-  if (priv->popup_widget)
-    {
-      gtk_combo_box_menu_destroy (combo_box);
-      gtk_menu_detach (GTK_MENU (priv->popup_widget));
-      priv->popup_widget = NULL;
-    }
-
   gtk_combo_box_create_child (combo_box);
 
-  gtk_combo_box_menu_setup (combo_box);
-
   if (gtk_tree_row_reference_valid (priv->active_row))
     {
       path = gtk_tree_row_reference_get_path (priv->active_row);
@@ -1385,25 +1403,6 @@ gtk_combo_box_menu_hide (GtkWidget *menu,
                                 FALSE);
 }
 
-static void
-gtk_combo_box_detacher (GtkWidget *widget,
-                        GtkMenu   *menu)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-  GtkComboBoxPrivate *priv = combo_box->priv;
-
-  g_return_if_fail (priv->popup_widget == (GtkWidget *) menu);
-
-  g_signal_handlers_disconnect_by_func (menu->priv->toplevel,
-                                        gtk_combo_box_menu_show,
-                                        combo_box);
-  g_signal_handlers_disconnect_by_func (menu->priv->toplevel,
-                                        gtk_combo_box_menu_hide,
-                                        combo_box);
-
-  priv->popup_widget = NULL;
-}
-
 static gboolean
 cell_layout_is_sensitive (GtkCellLayout *layout)
 {
@@ -1982,91 +1981,6 @@ gtk_combo_box_scroll_event (GtkWidget          *widget,
   return TRUE;
 }
 
-/*
- * menu style
- */
-static gboolean
-gtk_combo_box_row_separator_func (GtkTreeModel      *model,
-                                  GtkTreeIter       *iter,
-                                  GtkComboBox       *combo)
-{
-  GtkComboBoxPrivate *priv = combo->priv;
-
-  if (priv->row_separator_func)
-    return priv->row_separator_func (model, iter, priv->row_separator_data);
-
-  return FALSE;
-}
-
-static void
-gtk_combo_box_menu_setup (GtkComboBox *combo_box)
-{
-  GtkComboBoxPrivate *priv = combo_box->priv;
-  GtkWidget *menu;
-
-  g_signal_connect (priv->button, "button-press-event",
-                    G_CALLBACK (gtk_combo_box_menu_button_press),
-                    combo_box);
-
-  /* create our funky menu */
-  menu = _gtk_tree_menu_new_with_area (priv->area);
-  gtk_widget_set_name (menu, "gtk-combobox-popup-menu");
-
-  _gtk_tree_menu_set_model (GTK_TREE_MENU (menu), priv->model);
-
-  _gtk_tree_menu_set_wrap_width (GTK_TREE_MENU (menu), priv->wrap_width);
-  _gtk_tree_menu_set_row_span_column (GTK_TREE_MENU (menu), priv->row_column);
-  _gtk_tree_menu_set_column_span_column (GTK_TREE_MENU (menu), priv->col_column);
-
-  g_signal_connect (menu, "menu-activate",
-                    G_CALLBACK (gtk_combo_box_menu_activate), combo_box);
-
-  /* Chain our row_separator_func through */
-  _gtk_tree_menu_set_row_separator_func (GTK_TREE_MENU (menu),
-                                         (GtkTreeViewRowSeparatorFunc)gtk_combo_box_row_separator_func,
-                                         combo_box, NULL);
-
-  g_signal_connect (menu, "key-press-event",
-                    G_CALLBACK (gtk_combo_box_menu_key_press), combo_box);
-
-  /* Set up the popup menu */
-  if (priv->popup_widget)
-    gtk_menu_detach (GTK_MENU (priv->popup_widget));
-
-  priv->popup_widget = menu;
-
-  /*
-   * Note that we connect to show/hide on the toplevel, not the
-   * menu itself, since the menu is not shown/hidden when it is
-   * popped up while torn-off.
-   */
-  g_signal_connect (GTK_MENU (menu)->priv->toplevel, "show",
-                    G_CALLBACK (gtk_combo_box_menu_show), combo_box);
-  g_signal_connect (GTK_MENU (menu)->priv->toplevel, "hide",
-                    G_CALLBACK (gtk_combo_box_menu_hide), combo_box);
-
-  gtk_menu_attach_to_widget (GTK_MENU (menu),
-                             GTK_WIDGET (combo_box),
-                             gtk_combo_box_detacher);
-}
-
-static void
-gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
-{
-  GtkComboBoxPrivate *priv = combo_box->priv;
-
-  g_signal_handlers_disconnect_matched (priv->button,
-                                        G_SIGNAL_MATCH_DATA,
-                                        0, 0, NULL,
-                                        gtk_combo_box_menu_button_press, NULL);
-  g_signal_handlers_disconnect_matched (priv->popup_widget,
-                                        G_SIGNAL_MATCH_DATA,
-                                        0, 0, NULL,
-                                        gtk_combo_box_menu_activate, combo_box);
-
-  /* changing the popup window will unref the menu and the children */
-}
-
 /* callbacks */
 static gboolean
 gtk_combo_box_menu_button_press (GtkWidget      *widget,
@@ -2221,16 +2135,8 @@ gtk_combo_box_menu_key_press (GtkWidget   *widget,
 static GtkCellArea *
 gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout)
 {
-  GtkComboBox *combo = GTK_COMBO_BOX (cell_layout);
-  GtkComboBoxPrivate *priv = combo->priv;
-
-  if (G_UNLIKELY (!priv->area))
-    {
-      priv->area = gtk_cell_area_box_new ();
-      g_object_ref_sink (priv->area);
-    }
-
-  return priv->area;
+  GtkComboBox *combo_box = GTK_COMBO_BOX (cell_layout);
+  return combo_box->priv->area;
 }
 
 /*
@@ -2915,7 +2821,6 @@ gtk_combo_box_destroy (GtkWidget *widget)
       priv->box = NULL;
       priv->button = NULL;
       priv->arrow = NULL;
-      priv->cell_view = NULL;
       _gtk_bin_set_child (GTK_BIN (combo_box), NULL);
     }
 
@@ -3019,18 +2924,8 @@ gtk_combo_box_constructed (GObject *object)
 
   G_OBJECT_CLASS (gtk_combo_box_parent_class)->constructed (object);
 
-  if (!priv->area)
-    {
-      priv->area = gtk_cell_area_box_new ();
-      g_object_ref_sink (priv->area);
-    }
-
   gtk_combo_box_create_child (combo_box);
 
-  /* Create the popup menu, if it doesn’t already exist. */
-  if (!priv->popup_widget)
-    gtk_combo_box_menu_setup (combo_box);
-
   if (priv->has_entry)
     {
       priv->text_renderer = gtk_cell_renderer_text_new ();
@@ -3041,7 +2936,6 @@ gtk_combo_box_constructed (GObject *object)
     }
 }
 
-
 static void
 gtk_combo_box_dispose (GObject* object)
 {
@@ -3050,17 +2944,14 @@ gtk_combo_box_dispose (GObject* object)
 
   if (priv->popup_widget)
     {
-      gtk_combo_box_menu_destroy (combo_box);
+      /* Stop menu destruction triggering toggle on a now-invalid button */
+      g_signal_handlers_disconnect_by_func (priv->popup_widget,
+                                            gtk_combo_box_menu_hide,
+                                            combo_box);
       gtk_menu_detach (GTK_MENU (priv->popup_widget));
       priv->popup_widget = NULL;
     }
 
-  if (priv->area)
-    {
-      g_object_unref (priv->area);
-      priv->area = NULL;
-    }
-
   gtk_combo_box_unset_model (combo_box);
 
   G_OBJECT_CLASS (gtk_combo_box_parent_class)->dispose (object);
index 2e6ac30a2bf030fddba67462fe01037b04b6a3f9..0a8ac8ba987a27a07d4cc7d5cdaa60a3ba9ad507 100644 (file)
@@ -26,6 +26,7 @@
                 </child>
               </object>
             </child>
+            <signal name="button-press-event" handler="gtk_combo_box_menu_button_press" swapped="no" />
           </object>
           <packing>
             <property name="pack-type">end</property>
       </object>
     </child>
   </template>
+  <object class="GtkCellAreaBox" id="area" />
+  <object class="GtkTreeMenu" id="popup_widget">
+    <property name="cell-area">area</property>
+    <signal name="menu-activate" handler="gtk_combo_box_menu_activate" swapped="no" />
+    <signal name="key-press-event" handler="gtk_combo_box_menu_key_press" swapped="no" />
+    <signal name="show" handler="gtk_combo_box_menu_show" swapped="no" />
+    <signal name="hide" handler="gtk_combo_box_menu_hide" swapped="no" />
+  </object>
 </interface>